package org.ajwcc.pduUtils.test;

import java.lang.reflect.*;
import java.util.*;

import org.ajwcc.pduUtils.gsm3040.*;
import org.smslib.*;
import org.smslib.Message.*;

public class MessageGeneratorTester {

	public static void main(String[] args) throws Exception {
		String smscNo = "";
		int testCount = 0;
		int passCount = 0;

		// load a file for testing
		TestFileReader tfr = new TestFileReader();
		tfr.setSkipBlanksAndComment(false);

		tfr.init("java/org/ajwcc/pduUtils/testData/testMessages.txt");
		String currentLine;

		Message message = null;

		ArrayList<String> expectedPdus = new ArrayList<String>();

		main: while ((currentLine = tfr.next()) != null) {
			if (currentLine.trim().equals("")) {
				System.out.println(currentLine);
			} else if (currentLine.trim().startsWith("#")) {
				System.out.println(currentLine);
			} else {
				String[] data = new String[2];
				int colon = currentLine.indexOf(':');
				data[0] = currentLine.substring(0, colon);
				data[1] = currentLine.substring(colon + 1);

				if (data[0].equals("messageType")) {
					message = (Message) Class.forName(data[1]).newInstance();
					testCount++;
				} else if (data[0].equals("messageEnd")) {
					if (message != null) {
						// display pdus
						List<String> pdus = ((OutboundMessage) message)
								.getPdus(smscNo, 123);

						StringBuffer sb = new StringBuffer();
						for (String pduString : pdus) {
							Pdu pdu = new PduParser().parsePdu(pduString);

							System.out.println(pdu);

							if (message instanceof OutboundBinaryMessage) {
								sb.append(PduUtils.bytesToPdu(pdu
										.getUserDataAsBytes()));
							} else if (message instanceof OutboundMessage) {
								sb.append(pdu.getDecodedText());
							}
						}
						System.out.println("EXPECTED PDUs   : "
								+ expectedPdus.size());
						System.out.println("GENERATED PDUs  : " + pdus.size());

						if (message instanceof OutboundBinaryMessage) {
							OutboundBinaryMessage bin = (OutboundBinaryMessage) message;
							System.out.println("EXPECTED BYTES : "
									+ PduUtils.bytesToPdu(bin.getDataBytes()));
							System.out.println("GENERATED BYTES: "
									+ sb.toString());

							boolean match = sb.toString().equals(
									PduUtils.bytesToPdu(bin.getDataBytes()));
							System.out.println("MATCH: " + match);
							if (match)
								passCount++;
						} else if (message instanceof OutboundMessage) {
							System.out.println("EXPECTED TEXT : "
									+ message.getText());
							System.out.println("GENERATED TEXT: "
									+ sb.toString());

							boolean match = sb.toString().equals(
									message.getText());
							System.out.println("MATCH: " + match);
							if (match)
								passCount++;
						}
					}

					System.out.println();
					expectedPdus.clear();
					message = null;
					smscNo = "";
				} else if (data[0].equals("encoding")) {
					if (data[1].equals("7")) {
						((OutboundMessage) message)
								.setEncoding(MessageEncodings.ENC7BIT);
					} else if (data[1].equals("8")) {
						((OutboundMessage) message)
								.setEncoding(MessageEncodings.ENC8BIT);
					} else if (data[1].equals("ucs2")) {
						((OutboundMessage) message)
								.setEncoding(MessageEncodings.ENCUCS2);
					}
				} else if (data[0].equals("expectedPdu")) {
					expectedPdus.add(data[1]);
				} else if (data[0].equals("smscNumber")) {
					smscNo = data[1];
				} else if (data[0].equals("dataBytes")) {
					((OutboundBinaryMessage) message).setDataBytes(PduUtils
							.pduToBytes(data[1]));
				} else {
					// reflection
					// retrieve method getter for data[0]
					// get return type
					Class<?> currentClass = message.getClass();
					while (currentClass != Object.class) {
						try {
							Method getter = message.getClass().getMethod(
									"get"
											+ Character.toUpperCase(data[0]
													.charAt(0))
											+ data[0].substring(1));
							Class<?> returnType = getter.getReturnType();

							// retrieve setter for data[0]
							// invoke with the data[1] based on type
							Method setter = currentClass.getDeclaredMethod(
									"set"
											+ Character.toUpperCase(data[0]
													.charAt(0))
											+ data[0].substring(1), returnType);
							setter.setAccessible(true);
							setter.invoke(
									message,
									convertStringToArgument(returnType, data[1]));
							continue main;
						} catch (Exception e) {
							currentClass = currentClass.getSuperclass();
						}
					}
				}
			}
		}
		tfr.close();
		System.out.println();
		System.out.println("Total Tests: " + testCount);
		System.out.println("Passed: " + passCount);
	}

	public static Object convertStringToArgument(Class<?> c, String data) {
		if ((c == Boolean.class) || (c == Boolean.TYPE)) {
			return Boolean.valueOf(data);
		} else if ((c == Integer.class) || (c == Integer.TYPE)) {
			return Integer.valueOf(data);
		} else if ((c == Long.class) || (c == Long.TYPE)) {
			return Long.valueOf(data);
		} else if ((c == Integer.class) || (c == Integer.TYPE)) {
			return Integer.valueOf(data);
		} else if ((c == Short.class) || (c == Short.TYPE)) {
			return Short.valueOf(data);
		} else if (c == String.class) {
			return data;
		}

		return null;
	}
}
